package com.huawei.demo;

import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ConnectionException;
import com.huaweicloud.sdk.core.exception.RequestTimeoutException;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.ddm.v1.DdmClient;
import com.huaweicloud.sdk.ddm.v1.model.CreateDatabaseDetail;
import com.huaweicloud.sdk.ddm.v1.model.CreateDatabaseReq;
import com.huaweicloud.sdk.ddm.v1.model.CreateDatabaseRequest;
import com.huaweicloud.sdk.ddm.v1.model.CreateDatabaseResponse;
import com.huaweicloud.sdk.ddm.v1.model.DatabaseInstabcesParam;
import com.huaweicloud.sdk.ddm.v1.model.ListAvailableRdsListRequest;
import com.huaweicloud.sdk.ddm.v1.model.ListAvailableRdsListResponse;
import com.huaweicloud.sdk.ddm.v1.region.DdmRegion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

public class CreateDatabaseDemo {

    private static final Logger LOGGER = LoggerFactory.getLogger(CreateDatabaseDemo.class.getName());

    /**
     * args[0] = <<YOUR AK>>
     * args[1] = <<YOUR SK>>
     * args[2] = <<YOUR INSTANCE_ID>>
     * args[3] = <<YOUR REGION_ID>>
     * args[4] = <<数据库名>>
     * args[5] = <<分片数量>>
     * args[6] = <<数据节点实例访问账号>>
     * args[7] = <<数据节点实例访问密码>>
     **/
    public static void main(String[] args) {
        if (args.length != 8) {
            LOGGER.error("The expected number of parameters is 8");
            return;
        }

        String ak = args[0];
        String sk = args[1];
        String instanceId = args[2];
        String regionId = args[3];
        String dbName = args[4];
        int shardNum = Integer.parseInt(args[5]);

        // 创建逻辑拆分库会使用多个DN实例，此示例中预设该多个DN实例的管理员用户密码一致
        String adminUserOfDN = args[6];
        String adminPwdOfDN = args[7];

        ICredential auth = new BasicCredentials()
                .withAk(ak)
                .withSk(sk);
        DdmClient client = DdmClient.newBuilder()
                .withCredential(auth)
                .withRegion(DdmRegion.valueOf(regionId))
                .build();

        // 查询创建逻辑库可选取的数据节点实例列表
        // 查询所得的DN实例用于创建逻辑拆分库
        List<String> dnInstanceIds = listDataNodeInstances(client, instanceId);

        // 创建逻辑拆分库
        createLogicDatabase(client, instanceId, dbName, shardNum, dnInstanceIds, adminUserOfDN, adminPwdOfDN);
    }

    private static List<String> listDataNodeInstances(DdmClient client, String instanceId) {
        ListAvailableRdsListRequest request = new ListAvailableRdsListRequest();
        request.withInstanceId(instanceId);

        List<String> dnInstanceIds = new ArrayList<>();

        Consumer<ListAvailableRdsListRequest> consumer = (req) -> {
            ListAvailableRdsListResponse response = client.listAvailableRdsList(req);
            LOGGER.info(response.toString());
            if (!response.getInstances().isEmpty()) {
                dnInstanceIds.add(response.getInstances().get(0).getId());
            }
        };

        executeRequest(consumer, request);

        return dnInstanceIds;
    }

    private static void createLogicDatabase(DdmClient client, String instanceId, String dbName, int shardNum,
                                            List<String> useDataNodeIds, String dnUser, String dnPwd) {
        if (useDataNodeIds.isEmpty()) {
            LOGGER.error("DataNodes must not be empty.");
            return;
        }

        CreateDatabaseRequest request = buildCreateDBRequest(instanceId, dbName, shardNum, useDataNodeIds, dnUser, dnPwd);

        Consumer<CreateDatabaseRequest> consumer = (req) -> {
            CreateDatabaseResponse response = client.createDatabase(req);
            LOGGER.info(response.toString());
        };

        executeRequest(consumer, request);
    }

    private static CreateDatabaseRequest buildCreateDBRequest(String instanceId, String dbName, int shardNum,
        List<String> useDataNodeIds, String dnUser, String dnPwd) {
        List<DatabaseInstabcesParam> useDataNodes = new ArrayList<>();
        for (String dataNodeId : useDataNodeIds) {
            DatabaseInstabcesParam param = new DatabaseInstabcesParam();
            param.withId(dataNodeId)
                    .withAdminUser(dnUser)
                    .withAdminPassword(dnPwd);
            useDataNodes.add(param);
        }

        CreateDatabaseDetail detail = new CreateDatabaseDetail();
        detail.withName(dbName)
                .withShardMode(CreateDatabaseDetail.ShardModeEnum.CLUSTER)
                .withShardNumber(shardNum)
                .withUsedRds(useDataNodes);

        CreateDatabaseReq req = new CreateDatabaseReq().withDatabases(Collections.singletonList(detail));

        CreateDatabaseRequest request = new CreateDatabaseRequest();
        request.withInstanceId(instanceId)
                .withBody(req);

        return request;
    }

    private static <T> void executeRequest(Consumer<T> consumer, T request) {
        try {
            consumer.accept(request);
        } catch (ConnectionException e) {
            LOGGER.error("ConnectionException", e);
        } catch (RequestTimeoutException e) {
            LOGGER.error("RequestTimeoutException ", e);
        } catch (ServiceResponseException e) {
            LOGGER.error("httpStatusCode: {}, errorCode: {}, errorMsg: {}",
                    e.getHttpStatusCode(), e.getErrorCode(), e.getErrorMsg());
        } catch (Exception e) {
            LOGGER.error("Unexpected error occurred: ", e);
        }
    }

}
